from owlready2 import *

onto = get_ontology("http://test.org/onto.owl")

with onto:
    class Drug(Thing):
        pass
    # 活性成分
    class ActivePrinciple(Thing):
        pass
    class has_for_active_principle(Drug >> ActivePrinciple):
        pass
    # 非安慰剂: 含有某些活性成分
    class NonPlaceboDrug(Drug):
        equivalent_to = [Drug & has_for_active_principle.some(ActivePrinciple)]
    # 安慰剂: 不含活性成分
    class Placebo(Drug): 
        equivalent_to = [Drug & Not(has_for_active_principle.some(ActivePrinciple))]
    # 含有至少两种活性成分
    class DrugAssociation(Drug):
        equivalent_to = [Drug & has_for_active_principle.min(2, ActivePrinciple)]
    # 有效的约束: 
    # some : Property.some(Range_Class)
    # only : Property.only(Range_Class)
    # min : Property.min(cardinality, Range_Class)
    # max : Property.max(cardinality, Range_Class)
    # exactly : Property.exactly(cardinality, Range_Class)
    # value : Property.value(Range_Individual / Literal value)
    # has_self : Property.has_self(Boolean value)


def restrictions_on_property():
    print('1. restrictions_on_property')
    with onto:
        # 以is_a定义超类
        class my_property(Thing >> Thing): pass
        class Value(Thing): pass
        class MyClass(Thing):
            is_a = [my_property.some(Value)]
        # 限定可以通过is_a和equivalent_to添加到存在的类后面
        # some: 存在(existential)约束
        # only: 全称(universal)约束
        # relation: 类属性作为关联
        MyClass.is_a.append(my_property.some(Value))
        MyClass.equivalent_to.append(my_property.some(Value))
        print('\tMyClass.is_a: ', MyClass.is_a)
        print('\tMyClass.equivalent_to: ', MyClass.equivalent_to)

def restrictions_as_class_property():
    print('2. restrictions_as_class_property')
    with onto:
        print('\tNonPlaceboDrug.has_for_active_principle: ', NonPlaceboDrug.has_for_active_principle)

# 已定义类(defined_class)是被用于'equivalent_to'关系的类, 诸如Placebo、NonPlaceboDrug等
# 如果类被标记为已定义, owlready会自动生成equivalent_to公式, 同时考虑父类和属性
# 下面示例创建药品本体, 和一些健康条件
# 附加两个属性用于标记(indiciations)和禁忌症(contraindications)
# 使用SOME来约束标记, 用ONLY来约束禁忌症
# 创建药品的两个子类Antalgic, Aspirin被标记为已定义defined_class = True且他们的属性也如此
onto2 = get_ontology("http://test.org/onto2.owl")
with onto2:
    class Drug(Thing): pass
    class ActivePrinciple(Thing): pass
    class has_for_active_principle(Drug >> ActivePrinciple): pass

    class HeathCondition(Thing): pass
    class Pain(HeathCondition): pass
    # 中度疼痛
    class ModeratePain(Pain): pass
    # 心脏病
    class CardiacDisorder(HeathCondition): pass
    # 高血压
    class Hypertension(CardiacDisorder): pass

    # 怀孕
    class Pregnancy(HeathCondition): pass
    class Child(HeathCondition): pass
    class Bleeding(HeathCondition): pass

    class has_for_indications      (Drug >> HeathCondition): class_property_type = ["some"]
    class has_for_contraindications(Drug >> HeathCondition): class_property_type = ["only"]

    # 镇痛药
    class Antalgic(Drug):
        defined_class = True
        has_for_indications = [Pain]
        has_for_contraindications = [Pregnancy, Child, Bleeding]
    # 阿司匹林
    class Aspirin(Antalgic):
        defined_class = True
        has_for_indications = [ModeratePain]
        has_for_contraindications = [Pregnancy, Bleeding]
    # 降压药
    class Antihypertensive(Drug):
        equivalent_to = [Drug
            & has_for_indications.some(Hypertension)
            &has_for_contraindications.only(Pregnancy)]

def restriction_in_define_class_properties():
    print('3. restriction_in_define_class_properties')
    # Owlready会自动产生等效公式, 验证如下
    print('\tAntalgic.equivalent_to:', Antalgic.equivalent_to)
    print('\tAspirin.equivalent_to', Aspirin.equivalent_to)
    print('\tAntihypertensive.has_for_indications', Antihypertensive.has_for_indications)
    print('\tAntihypertensive.has_for_contraindications', Antihypertensive.has_for_contraindications)

def logic_operator():
    # owlready支持逻辑操作在类之间(以及类构造器, 限制restrictions)
    # &, |, Not()
    print('4. logic_operator')

def one_of():
    print('5. one_of')
    with onto:
        class DrugForm(Thing): pass
        tablet = DrugForm()
        capsule = DrugForm()
        injectable = DrugForm()
        pomade = DrugForm()
        DrugForm.is_a.append(OneOf([tablet, capsule, injectable, pomade]))

def inverse_of():
    print('6. inverse_of')
    # inverse构造器支持根据一个属性创建一个新的逆属性
    Inverse(has_for_active_principle)

def constrain_datatype():
    print('7. constrain_datatype')
    # 约束类型
    ConstrainedDatatype(int, min_inclusive=0, max_inclusive=20)
    ConstrainedDatatype(str, max_length = 100)
    # length
    # min_length
    # max_length
    # pattern
    # white_space
    # max_inclusive
    # max_exclusive
    # min_inclusive
    # min_exclusive
    # total_digits
    # fraction_digits

def property_chain():
    with onto:
        class prop1(Thing >> Thing): pass
        class prop2(Thing >> Thing): pass
        PropertyChain([prop1, prop2])

restrictions_on_property()
restrictions_as_class_property()
restriction_in_define_class_properties()
logic_operator()
one_of()
inverse_of()
constrain_datatype()
property_chain()



